import { parseUtf8 } from '../utils/utils'

export interface CodecType {

    encode: (buf: number[], index: number) => void,
    decode: (buf: number[], index: number) => void,
    size: () => number,
}


export class Uint8 implements CodecType {

    value: number;

    constructor(value: number = 0) {
        this.value = value;
    }

    encode = (buf: number[], index: number) => {
        buf[index] = this.value & 0xFF;
    }

    decode = (buf: number[], index: number) => {
        this.value = buf[index];
    }

    size = () => {
        return 1;
    }
}


export class Uint16 implements CodecType {

    value: number;

    constructor(value: number = 0) {
        this.value = value;
    }

    encode = (buf: number[], index: number) => {
        buf[index] = (this.value >> 8) & 0xFF;
        buf[index + 1] = this.value & 0xFF;
    }

    decode = (buf: number[], index: number) => {
        this.value = (buf[index] << 8) + buf[index + 1];
    }

    size = () => {
        return 2;
    }
}

export class Uint32 implements CodecType {

    value: number;

    constructor(value: number = 0) {
        this.value = value;
    }

    encode = (buf: number[], index: number) => {
        buf[index] = (this.value >> 24) & 0xFF;
        buf[index + 1] = (this.value >> 16) & 0xFF;
        buf[index + 2] = (this.value >> 8) & 0xFF;
        buf[index + 3] = this.value & 0xFF;
    }

    decode = (buf: number[], index: number) => {
        this.value = (buf[index] << 24) + (buf[index + 1] << 16) + (buf[index + 2] << 8) + buf[index];
    }

    size = () => {
        return 4;
    }
}

export class ByteView implements CodecType {

    buf: number[];
    index: number;
    len: number;

    constructor(buf: number[] = [], index: number = 0, len: number = buf.length - index) {
        this.buf = buf;
        this.index = index;
        this.len = len;
    }

    encode = (buf: number[], index: number) => {
        buf[index] = this.len;
        for (let i = 0; i < this.len; i ++) {
            buf[index + i + 1] = this.buf[this.index + i];
        }
    }

    decode = (buf: number[], index: number) => {
        this.buf = buf;
        this.index = index + 1;
        this.len = buf[0];
    }

    size = () => {
        return this.len + 1;
    }

    toString = () => {
        return parseUtf8(this.buf.slice(this.index, this.index + this.len));
    }
}


